package com.sys.service.impl;

import com.bhudy.base.BaseServiceImpl;
import com.bhudy.base.QueryFilter;
import com.bhudy.enums.Relation;
import com.sys.entity.SysCrontab;
import com.sys.service.SysCrontabService;
import com.sys.service.SysCrontabTypeService;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;

/**
 * @Author com.bhudy
 * @Description SysCrontabService
 * @Date Mon Nov 04 14:28:07 CST 2019
 */
@Service
public class SysCrontabServiceImpl extends BaseServiceImpl<SysCrontab, Serializable> implements SysCrontabService {

    @Autowired
    private SysCrontabTypeService sysCrontabTypeService;
    private static SchedulerFactory gSchedulerFactory = new StdSchedulerFactory();
    private static Scheduler sched;

    static {
        if (sched == null) {
            try {
                sched = gSchedulerFactory.getScheduler();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void startQuartzJobAll() {
        QueryFilter queryFilter = new QueryFilter().and("status", Relation.NOT_EQUAL, 1);
        List<SysCrontab> sysCrontabList = super.findList(queryFilter);
        if (sysCrontabList != null && sysCrontabList.size() != 0) {
            for (SysCrontab sysCrontab : sysCrontabList) {
                try {
                    this.createCrontabJob(sysCrontab);
                } catch (Exception e) {
                    sysCrontab.setTaskStatus(1);
                    super.update(sysCrontab);
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 新增任务 调用方法
     */
    @Override
    public void createCrontabJob(SysCrontab sysCrontab) throws Exception {
        if (sysCrontab.getIsOpen() == 1) return;
        // 找到当前任务类型对应class
        Class cls = sysCrontabTypeService.checkJobClass(sysCrontab.getSysCrontabTypeId());

        //每次都是动态的根据表中用户配置
        if (sysCrontab.getIsRepeat() == 0) {
            // 等于0 只执行一次
            addQuartzJob(sysCrontab.getName(), cls, sysCrontab.getStartTime(), sysCrontab.getId());
        } else {
            //否则是需要利用cron 表达式执行的任务
            addQuartzJob(sysCrontab.getName(), cls, sysCrontab.getCronTime(), sysCrontab.getId());
        }
    }

    /**
     * @param jobName   任务名
     * @param jobClass  任务
     * @param startTime 时间设置 当前任务不重复执行开始时间
     */
    @Override
    public void addQuartzJob(String jobName, Class jobClass, Date startTime, Long sysCrontabId) throws SchedulerException {
        JobDetail jobDetail = newJob(jobClass).build();
        Trigger trigger = newTrigger()
                .withIdentity(sysCrontabId.toString())
                .usingJobData(SysCrontab.JOB_NAME, jobName)
                .usingJobData(SysCrontab.CRONTAB_ID, sysCrontabId)
                .withSchedule(simpleSchedule())
                .startAt(startTime).build();
        sched.scheduleJob(jobDetail, trigger);
        // 启动
        if (!sched.isShutdown()) {
            sched.start();
        }
    }

    /**
     * @param jobName  任务名
     * @param jobClass 对应任务 jobClass
     * @param time     cron表达式
     * @Description: 添加一个定时任务
     */
    @Override
    public void addQuartzJob(String jobName, Class jobClass, String time, Long sysCrontabId) throws SchedulerException {
        // JobDetail jobDetail = newJob(jobClass).withIdentity(jobName, GROUP_NAME).build();// 任务名，任务组，任务执行类
        JobDetail jobDetail = newJob(jobClass).build();
        // 触发器
        Trigger trigger = newTrigger()
                .withIdentity(sysCrontabId.toString())
                //把一些 任务 key - value 存到当前任务中 例如备注
                .usingJobData(SysCrontab.JOB_NAME, jobName)
                .usingJobData(SysCrontab.CRONTAB_ID, sysCrontabId)
                .withSchedule(cronSchedule(time)).startNow().build();
        sched.scheduleJob(jobDetail, trigger);
        // 启动
        if (!sched.isShutdown()) {
            sched.start();
        }
    }

    /**
     * @param sysCrontabId
     * @Description: 移除一个任务(使用默认的任务组名触发器名触发器组名)
     */
    @Override
    public void removeQuartzJob(Long sysCrontabId) throws SchedulerException {
        sched.pauseTrigger(TriggerKey.triggerKey(sysCrontabId.toString()));// 停止触发器
        sched.unscheduleJob(TriggerKey.triggerKey(sysCrontabId.toString()));// 移除触发器
        //上面两个api 有可能已经删除了对应job
        Trigger trigger = sched.getTrigger(TriggerKey.triggerKey(sysCrontabId.toString()));
        if (trigger != null) {
            sched.deleteJob(trigger.getJobKey());// 删除任务
        }
    }

    /**
     * @Description: 修改一个任务的触发时间
     */
    @Override
    public void modifyQuartzJobTime(Long crontabId) throws Exception {
        SysCrontab sysCrontab = super.get(crontabId);
        //获取当前 jobName 和组下的trigger
        Trigger trigger = sched.getTrigger(TriggerKey.triggerKey(crontabId.toString()));
        if (trigger != null) {
            //如果当前任务不存在
            removeQuartzJob(crontabId);
        }
        createCrontabJob(sysCrontab);
    }

}
